#!/usr/bin/perl

use strict;
use Fcntl;
use IO::Seekable;
use Getopt::Std;
use lib 'lib';
use CRC;

$| = 1;

my %opts = ();
getopts('h:d:', \%opts);

my $ch = $opts{'h'};
my $dir = $opts{'d'};

if ($ch eq '' || $dir eq '') {
	die "Usage: $0 -h CH -d DIR\n";
}

$dir =~ s/\/$//;

my $packetsize = 1;
my $error = 0;
my $status = 0;

my $TS = undef;
my $IDX = undef;

my $tot = undef;
my $hour = -1;
my $bytes = 0;

while(read(STDIN, my $buf, $packetsize)) {
	my $pos = 0;
	my $sync_byte = vec($buf, $pos++, 8);

	if ($sync_byte == 0x47) {
		$packetsize = 188;

		while(length($buf) < 188 && read(STDIN, my $append, 1)) {
			$buf .= $append;
		}

		my $a = vec($buf, $pos++, 8);
		my $b = vec($buf, $pos++, 8);
		my $transport_error_indicator = $a >> 7 & 0x01;
		my $payload_unit_start_indicator = $a >> 6 & 0x01;
		my $pid = ($a & 0x1F) << 8 | $b;

		if ($transport_error_indicator) {
			$error++;
		}

		my $a = vec($buf, $pos++, 8);
		my $adaptation_field_control = $a >> 4 & 0x03;

		if ($adaptation_field_control & 0x02) {
			my $adaptation_field_length = vec($buf, $pos++, 8);
			$pos += $adaptation_field_length;
		}

		if ($pid == 0x0014) {
			if ($payload_unit_start_indicator) {
				my $pointer_field = vec($buf, $pos++, 8);

				if ($pointer_field == 0) {
					$tot = &tot($buf);

					if (defined $tot) {
						if ($hour != $tot->{hour}) {
							if ($TS) {
								close($TS);
								close($IDX);

								$error = 0;
								$bytes = 0;
							}

							my($yy, $mm, $dd, $hh, $ii, $ss) = &mjdToDate($tot);
							my $sy = substr($yy, -2);
							my $date = sprintf("%02d%02d%02d", $sy, $mm, $dd);
							my $file = sprintf("%02d%02d%02d%02d_Ch%02d", $sy, $mm, $dd, $hh, $ch);
							my $tsdir = sprintf("%s/%s", $dir, $date);
							my $tsfile = sprintf("%s/%s.ts", $tsdir, $file);
							my $idxfile = sprintf("%s/%s.idx", $tsdir, $file);
							system("/bin/mkdir -p $tsdir");

							sysopen($TS, $tsfile, O_WRONLY | O_CREAT | O_APPEND);
							sysopen($IDX, $idxfile, O_WRONLY | O_CREAT | O_APPEND);

#							select($TS);  $| = 1; select(STDOUT);
							select($IDX); $| = 1; select(STDOUT);

							$bytes += sysseek($TS, 0, SEEK_END);
							$hour = $tot->{hour};
						}

						print $IDX pack('nCCCL', $tot->{mjd}, $tot->{hour}, $tot->{min}, $tot->{sec}, $bytes);
					}
				}
			}
		}

		if ($status <= 0) {
			my($yy, $mm, $dd, $hh, $ii, $ss) = &mjdToDate($tot);
			my $date = sprintf('%04d/%02d/%02d %02d:%02d:%02d', $yy, $mm, $dd, $hh, $ii, $ss);
			$0 = "REC [err:$error] [$ch] $date";
			$status = 1000;
		}

		$status--;

		if ($TS) {
			print $TS $buf;
			$bytes += 188;
		}

	} else {
		$packetsize = 1;
		$error++;
	}
}

sub tot {
	my($buf) = @_;

	my $pos = 5;
	my $ret = {};

	my $table_id = vec($buf, $pos++, 8);

	my $a = vec($buf, $pos++, 8);
	my $b = vec($buf, $pos++, 8);
	my $section_length = ($a & 0x0F) << 8 | $b;
	my $program_endbyte = $pos + $section_length;

	if ($table_id == 0x70 || $table_id == 0x73) {
		my $a = vec($buf, $pos++, 8);
		my $b = vec($buf, $pos++, 8);
		$ret->{mjd} = $a << 8 | $b;

		$ret->{hour} = vec($buf, $pos++, 8);
		$ret->{min} = vec($buf, $pos++, 8);
		$ret->{sec} = vec($buf, $pos++, 8);

		my $a = vec($buf, $pos++, 8);
		my $b = vec($buf, $pos++, 8);
		my $descriptors_loop_length = ($a & 0x0F) << 8 | $b;
		my $descriptor_loop_endbyte = $pos + $descriptors_loop_length;

		while ($pos < $descriptor_loop_endbyte) {
			my $descriptor_tag = vec($buf, $pos++, 8);
			my $descriptor_length = vec($buf, $pos++, 8);
			$pos += $descriptor_length;
		}

		my $_crc32 = CRC::crc32(substr($buf, 5, $pos - 5));

		my $a = vec($buf, $pos++, 8);
		my $b = vec($buf, $pos++, 8);
		my $c = vec($buf, $pos++, 8);
		my $d = vec($buf, $pos++, 8);
		my $crc32 = $a << 24 | $b << 16 | $c << 8 | $d;

		if ($crc32 != $_crc32) {
			return undef;
		}

		return $ret;
	}

	return undef;
}

sub mjdToDate {
	my($src) = @_;

	if (!defined $src) {
		return ();
	}

	my $yy = int(($src->{mjd} - 15078.2) / 365.25);
	my $mm = int(($src->{mjd} - 14956.1 - int($yy * 365.25)) / 30.6001);
	my $dd = int($src->{mjd} - 14956 - int($yy * 365.25) - int($mm * 30.6001));

	if (13 < $mm) {
		$yy = $yy + 1;
		$mm = $mm - 12;
	}

	$yy = $yy + 1900;
	$mm = $mm - 1;

	my $hh = (($src->{hour} >> 4) & 0x0F) * 10 + ($src->{hour} & 0x0F);
	my $ii = (($src->{min} >> 4) & 0x0F) * 10 + ($src->{min} & 0x0F);
	my $ss = (($src->{sec} >> 4) & 0x0F) * 10 + ($src->{sec} & 0x0F);

	return ($yy, $mm, $dd, $hh, $ii, $ss);
}

